home *** CD-ROM | disk | FTP | other *** search
- /*------------------------------------------------------------------------
- * $Header: /d1/carlson/programs/misc/RCS/gpasswd.c,v 1.3 1991/07/19 15:33:23 carlson Exp $
- *
- * gpasswd This program is identical to passwd except sets the
- * password for a group.
- *
- * Format of call:
- * gpasswd [group]
- *
- * Where:
- * group Is an optional group name to change. The user must be
- * in the list of users allowed to be in the group to
- * change the group password. If 'group' is not specified,
- * the user's current group will be assumed.
- *
- * Features:
- * - If user is root, does not ask for current password.
- * - If no password exists yet, does not ask for current password.
- * - If YP entry, keeps it a YP entry.
- *
- * Discussion:
- * This is just some discussion on how the group password works and
- * how groups are used in UNIX.
- *
- * To change groups, the 'newgrp' command is used providing the new
- * group to be changed to as a parameter. If the user is root or in
- * the list in /etc/group for the new group, newgrp starts a new shell
- * (using whatever shell is the default shell) having the new group
- * as its group ID. Note: To return to the old group, all one has to
- * do is exit the current shell.
- *
- * If the user is not in the list of accepted users for a group, newgrp
- * will ask for a password (if one exists in /etc/group). If no password
- * exists and the user is not in the list, newgrp will not allow the
- * change. If a password is present and the user enters it correctly,
- * newgrp will start a new shell having the new group as its group ID.
- *
- *
- * Revision History:
- * $Log: gpasswd.c,v $
- * Revision 1.3 1991/07/19 15:33:23 carlson
- * Added Header for RCS. Fixed up documentation.
- *
- * Revision 1.2 90/11/27 10:39:57 chris
- * Added debug symbols.
- *
- * Revision 1.1 90/10/09 17:25:47 chris
- * Initial revision
- *
- * 11/ 4/89 Christopher W. Carlson - Silicon Graphics Inc.
- * Initial draft
- *
- *-----------------------------------------------------------------------*/
-
- #include <stdio.h>
- #include <pwd.h>
- #include <ctype.h>
-
- /*-----
- * DEBUG Enable debugging so actual group file is NOT modified.
- * DEBUGP Enable print statements.
- */
-
- /* #define DEBUG */
- /* #define DEBUGP */
-
- typedef enum {FALSE = 0, TRUE} bool;
-
- extern char *getlogin (), *getpass (), *index (), *crypt ();
-
- #ifdef DEBUG
- char grpfil[] = "group";
- char tmpfil[] = "$new$group";
- #else
- char grpfil[] = "/etc/group";
- char tmpfil[] = "/etc/$new$group";
- #endif
-
- char usernam[L_cuserid], grpnam[L_cuserid] = "", newpass[128];
- char fline[256], salt[3], ctmp[128];
- char ctemp[256], *g_name, *g_pwd, *g_users;
- int g_id;
- bool YPentry;
-
- char charset[] =
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
-
- main (argc, argv)
- int argc;
- char *argv[];
- {
- register int i; /* Just temporary storage */
- register FILE *ifp, *ofp; /* For old and new group file */
- int uid, gid; /* Our UID and GID to change */
- char *login; /* To know our name */
- struct passwd *cur_pwd; /* For finding out our name */
- char *cptr; /* For scanning strings */
- bool b;
-
- /*----
- * Initialize uid with the user ID and gid with the group
- * ID of the process.
- *----*/
-
- uid = getuid ();
- gid = getgid ();
-
- #ifdef DEBUGP
- fprintf (stderr, "UID = %d, GID = %d\n", uid, gid);
- #endif
-
- /*----
- * Now, figure out the user's name from the UID.
- *----*/
-
- if ((cuserid (usernam) == NULL) || (usernam[0] == '\0')) {
- if ((login = getlogin ()) == NULL) {
- if ((cur_pwd = getpwuid (uid)) == NULL) {
- fprintf (stderr, "gpasswd: Cannot find user name\n");
- exit (1);
- } else {
- strcpy (usernam, cur_pwd->pw_name);
- }
- } else {
- strcpy (usernam, login);
- }
- }
-
- #ifdef DEBUGP
- fprintf (stderr, "Username = %s\n", usernam);
- #endif
-
- /*----
- * Read the command line parameters. Only one is expected
- * and this should be a group name. If no parameter was
- * given, skip saving it.
- *----*/
-
- if (argc > 1) {
- strcpy (grpnam, argv[1]);
- #ifdef DEBUGP
- fprintf (stderr, "Group name provided = %s\n", grpnam);
- #endif
- }
-
- /*----
- * Open the input group file.
- *----*/
-
- if ((ifp = fopen (grpfil, "r")) == NULL) {
- fprintf (stderr, "gpasswd: Cannot open %s\n", grpfil);
- exit (1);
- }
-
- /*----
- * Open the output group file. Use a funky name for now.
- *----*/
-
- if ((ofp = fopen (tmpfil, "w")) == NULL) {
- fprintf (stderr, "gpasswd: Cannot create new group file\n");
- exit (1);
- }
-
- /*----
- * Search for desired group entry writing unused entries
- * to output group file. 'b' = TRUE if group entry found.
- *----*/
-
- b = FALSE;
- while (fgets (fline, 256, ifp)) {
-
- #ifdef DEBUGP
- fprintf (stderr, "group - %s", fline);
- #endif
- parse (fline);
- if (grpnam[0] == '\0') {
- if (gid == g_id) {
- b = TRUE;
- break;
- }
- } else {
- if (strcmp (grpnam, g_name) == 0) {
- b = TRUE;
- break;
- }
- }
- fputs (fline, ofp);
-
- #ifdef DEBUGP
- fprintf (stderr, " skipped\n");
- #endif
- }
-
- /*----
- * Verify that the group is good and that the user has the
- * right to change the password.
- *----*/
-
- if (!b) {
- if (grpnam[0] == '\0') {
- fprintf (stderr, "gpasswd: Group entry %d not found\n", gid);
- } else {
- fprintf (stderr, "gpasswd: Group entry %s not found\n", grpnam);
- }
- fclose (ofp);
- unlink (tmpfil);
- exit (1);
- }
-
- if (uid != 0) { /* If not root */
-
- #ifdef DEBUGP
- fprintf (stderr, "Searching user's name\n");
- #endif
- b = FALSE; /* TRUE if user in list */
- for (cptr = g_users; *cptr != '\0'; cptr += strlen (cptr) + 1) {
-
- #ifdef DEBUGP
- fprintf (stderr, " %s...", cptr);
- #endif
- if (strcmp (cptr, usernam) == 0) {
-
- #ifdef DEBUGP
- fprintf (stderr, "found\n");
- #endif
- b = TRUE;
- break;
- }
- #ifdef DEBUGP
- fprintf (stderr, "nope\n");
- #endif
- }
- if (!b) {
- if (grpnam[0] == '\0') {
- fprintf (stderr,
- "gpasswd: You are not authorized to change the password for %d\n",
- gid);
- } else {
- fprintf (stderr,
- "gpasswd: You are not authorized to change the password for %s\n",
- grpnam);
- }
- fclose (ofp);
- unlink (tmpfil);
- exit (1);
- }
- }
-
- /*----
- * If the user is not root and there is a password, make the
- * user enter the old password.
- *----*/
-
- if (uid != 0) {
- if (*g_pwd != '\0') {
- cptr = getpass ("Enter old password: ");
- strcpy (ctmp, cptr);
- salt[0] = g_pwd[0];
- salt[1] = g_pwd[1];
- salt[2] = '\0';
- cptr = crypt (ctmp, salt);
- if (strcmp (cptr, g_pwd) != 0) {
- fprintf (stderr, "gpasswd: Password incorrect\n");
- fclose (ofp);
- unlink (tmpfil);
- exit (1);
- }
- }
- }
-
- /*----
- * Now have the user enter the new password. Verify by
- * having him enter it again.
- *----*/
-
- cptr = getpass ("Enter new password: ");
- strcpy (newpass, cptr);
- cptr = getpass ("Enter new password again: ");
-
- if (strcmp (newpass, cptr) != 0) {
- fprintf (stderr, "gpasswd: Passwords don't match\n");
- fclose (ofp);
- unlink (tmpfil);
- exit (1);
- }
-
- /*----
- * Encrypt password.
- *----*/
-
- srand (time (NULL)); /* Randomize random number generator */
- salt[0] = charset[(rand () % sizeof (charset))];
- salt[1] = charset[(rand () % sizeof (charset))];
- salt[2] = '\0';
- cptr = crypt (newpass, salt);
-
- /*----
- * Write new line out.
- *----*/
-
- if (YPentry) {
- sprintf (fline, "+%s:%s:%d:", g_name, cptr, g_id);
- } else {
- sprintf (fline, "%s:%s:%d:", g_name, cptr, g_id);
- }
- for (cptr = g_users; *cptr; cptr += strlen (cptr) + 1) {
- strcat (fline, cptr);
- strcat (fline, ",");
- }
-
- i = strlen (fline) - 1;
- if (fline[i] == ',')
- fline[i] = '\0';
- strcat (fline, "\n");
-
- fputs (fline, ofp);
-
- /*----
- * Now write out rest of file.
- *----*/
-
- while (fgets (fline, 256, ifp)) {
- fputs (fline, ofp);
- }
-
- /*----
- * Close files and rename new one to replace old one.
- *----*/
-
- fclose (ifp);
- fclose (ofp);
- unlink (grpfil);
- rename (tmpfil, grpfil);
- }
-
- /*--------------------------------------------------------------------------
- * parse This routine parses the line passed to it assuming it is
- * of the format for the /etc/group file. The following
- * values are set. Note: String to be parsed is copied to
- * ctemp in it's entirety.
- *
- * YPentry TRUE/FALSE depending on whether line started with "+".
- * g_name Points to position in ctemp where group name starts.
- * Group name string will be terminated with '\0'.
- * g_pwd Points to position in ctemp where password begins.
- * Password string will be terminated with '\0'.
- * g_users Points to position in ctemp where first user name is.
- * Each user name will be null terminated with the next
- * user name following. If the first character of the user
- * name is null, no further user names exist.
- * g_id Group ID number.
- *-------------------------------------------------------------------------*/
-
- parse (str)
- char *str;
- {
- register char *tstr;
-
- /*----
- * Initialize pointers to null string.
- *----*/
-
- YPentry = FALSE;
- g_name = g_pwd = g_users = "";
- g_id = -1;
-
- /*----
- * Copy string to ctemp for parsing. Also, remove '\n' from
- * end of ctemp. Set tstr to start of ctemp.
- *----*/
-
- strcpy (ctemp, str);
- if ((tstr = index (ctemp, '\n')))
- *tstr = '\0';
- tstr = ctemp;
-
- #ifdef DEBUGP
- fprintf (stderr, " Parsing %s\n", ctemp);
- #endif
-
- /*----
- * Determine if a YP entry.
- *----*/
-
- if (*tstr == '+') {
- YPentry = TRUE;
- tstr++;
- }
-
- #ifdef DEBUGP
- fprintf (stderr, " YPentry = %s\n", (YPentry) ? "TRUE" : "FALSE");
- #endif
-
- if (*tstr == '\0')
- return;
-
- /*----
- * Get group name and null terminate.
- *----*/
-
- g_name = tstr;
- tstr = index (tstr, ':');
- if (tstr) {
- *tstr++ = '\0';
- #ifdef DEBUGP
- fprintf (stderr, " group name = %s\n", g_name);
- #endif
- } else {
- #ifdef DEBUGP
- fprintf (stderr, " group name = %s\n", g_name);
- #endif
- return;
- }
-
- /*----
- * Get password and null terminate.
- *----*/
-
- g_pwd = tstr;
- tstr = index (tstr, ':');
- if (tstr) {
- *tstr++ = '\0';
- #ifdef DEBUGP
- fprintf (stderr, " password = %s\n", g_pwd);
- #endif
- } else {
- #ifdef DEBUGP
- fprintf (stderr, " password = %s\n", g_pwd);
- #endif
- return;
- }
-
- /*----
- * Get group ID and null terminate.
- *----*/
-
- g_id = atoi (tstr);
- tstr = index (tstr, ':');
- if (tstr) {
- *tstr++ = '\0';
- #ifdef DEBUGP
- fprintf (stderr, " ID = %d\n", g_id);
- #endif
- } else {
- #ifdef DEBUGP
- fprintf (stderr, " ID = %d\n", g_id);
- #endif
- return;
- }
-
- /*----
- * Get list of users and null terminate.
- *----*/
-
- g_users = tstr;
- while ((tstr = index (tstr, ','))) {
- *tstr++ = '\0';
- }
- }
-